package tk.mybatis.template.annotation;


import tk.mybatis.mapper.entity.Condition;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.template.exception.ServiceException;
import tk.mybatis.template.util.EmptyUtil;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 重写条件查询
 * @author wuxiaopeng
 */
public class ConditionRewrite {
    /**
     * 解析mp注解条件
     *
     * @param condition 条件类
     * @param param     查询参数
     * @return Condition 条件对象
     */
    public static Condition equalToCondition(Condition condition, Object param) {
        Condition.Criteria criteria = condition.createCriteria();
        Map<String, Object> map = new HashMap<>();
        try {
            // 得到类对象
            Class<?> clazz = param.getClass();
            for (Field field : clazz.getDeclaredFields()) {
                //字段属性
                String property;
                field.setAccessible(true);
                String fieldName = field.getName();
                Object value = field.get(param);
                ParamCondition mapperParam = field.getAnnotation(ParamCondition.class);
                if (mapperParam != null && (EmptyUtil.isNotEmpty(value) || "order".equals(mapperParam.order()))) {
                    String entityName = mapperParam.entityName();
                    property = EmptyUtil.isEmpty(entityName) ? fieldName : entityName;
                    if ("and".equals(mapperParam.patternType())) {
                        if (EmptyUtil.isNotEmpty(mapperParam.pattern())) {
                            criteria = andJudgePattern(criteria, mapperParam.pattern(), property, value, mapperParam.fuzzyPosition());
                        }
                    } else if ("or".equals(mapperParam.patternType())) {
                        if (EmptyUtil.isNotEmpty(mapperParam.pattern())) {
                            criteria = orJudgePattern(criteria, mapperParam.pattern(), property, value, mapperParam.fuzzyPosition());
                        }
                    } else {
                        throw new RuntimeException("查询连接符号【" + mapperParam.patternType() + "】不存在！");
                    }

                    //排序
                    if ("order".equals(mapperParam.order())) {
                        if ("desc".equals(mapperParam.orderType())) {
                            condition.orderBy(property).desc();
                        } else if ("asc".equals(mapperParam.orderType())) {
                            condition.orderBy(property).asc();
                        } else {
                            throw new RuntimeException("排序类型【" + mapperParam.orderType() + "】不存在！");
                        }
                    } else if (EmptyUtil.isNotEmpty(mapperParam.order())) {
                        throw new RuntimeException("排序符号【" + mapperParam.order() + "】不存在！");
                    }
                }else {
                    if (EmptyUtil.isNotEmpty(value)) {
                        map.put(fieldName, value);
                    }
                }
            }
        } catch (Exception e) {
            throw new ServiceException(e.getMessage(), e);
        }
        criteria.andEqualTo(map);
        return condition;
    }

    private static Example.Criteria andJudgePattern(Example.Criteria criteria, String pattern,
                                                    String property, Object value, String fuzzyPosition) {
        switch (pattern) {
            case "is not null":
                criteria.andIsNotNull(property);
                break;
            case "=":
                criteria.andEqualTo(property, value);
                break;
            case "!=":
                criteria.andNotEqualTo(property, value);
                break;
            case ">":
                criteria.andGreaterThan(property, value);
                break;
            case ">=":
                criteria.andGreaterThanOrEqualTo(property, value);
                break;
            case "<":
                criteria.andLessThan(property, value);
                break;
            case "<=":
                criteria.andLessThanOrEqualTo(property, value);
                break;
            case "in":
                criteria.andIn(property, Arrays.asList((Object[]) value));
                break;
            case "not in":
                criteria.andNotIn(property, Arrays.asList((Object[]) value));
                break;
            case "like":
                criteria.andLike(property, String.valueOf(getFuzzyPosition(value, fuzzyPosition)));
                break;
            case " not like":
                criteria.andNotLike(property, String.valueOf(getFuzzyPosition(value, fuzzyPosition)));
                break;
            default:
                throw new RuntimeException("查询符号:【" + pattern + "】不存在！");
        }
        return criteria;
    }

    private static Example.Criteria orJudgePattern(Example.Criteria criteria, String pattern,
                                                   String property, Object value, String fuzzyPosition) {
        switch (pattern) {
            case "is not null":
                criteria.orIsNotNull(property);
                break;
            case "=":
                criteria.orEqualTo(property, value);
                break;
            case "!=":
                criteria.orNotEqualTo(property, value);
                break;
            case ">":
                criteria.orGreaterThan(property, value);
                break;
            case ">=":
                criteria.orGreaterThanOrEqualTo(property, value);
                break;
            case "<":
                criteria.orLessThan(property, value);
                break;
            case "<=":
                criteria.orLessThanOrEqualTo(property, value);
                break;
            case "in":
                criteria.orIn(property, Arrays.asList((Object[]) value));
                break;
            case "not in":
                criteria.orNotIn(property, Arrays.asList((Object[]) value));
                break;
            case "like":
                criteria.orLike(property, String.valueOf(String.valueOf(getFuzzyPosition(value, fuzzyPosition))));
                break;
            case " not like":
                criteria.orNotLike(property, String.valueOf(String.valueOf(getFuzzyPosition(value, fuzzyPosition))));
                break;
            default:
                throw new RuntimeException("查询符号:【" + pattern + "】不存在！");
        }
        return criteria;
    }

    private static Object getFuzzyPosition(Object value, String fuzzyPosition) {
        if ("before".equals(fuzzyPosition)) {
            value = "%" + value;
        } else if ("after".equals(fuzzyPosition)) {
            value = value + "%";
        } else if ("all".equals(fuzzyPosition)) {
            value = "%" + value + "%";
        } else {
            throw new RuntimeException("模糊查询符号【" + fuzzyPosition + "】不存在！");
        }
        return value;
    }

    private static Object getOrderType(Object value, String fuzzyPosition) {
        if ("before".equals(fuzzyPosition)) {
            value = "%" + value;
        } else if ("after".equals(fuzzyPosition)) {
            value = value + "%";
        } else if ("all".equals(fuzzyPosition)) {
            value = "%" + value + "%";
        } else {
            throw new RuntimeException("模糊查询符号【" + fuzzyPosition + "】不存在！");
        }
        return value;
    }
}
